/*
* dataStore via JSON - DS
* TODO
* reload
* fillSelect
* fillTable
* implement write, create, delete
* AJAX Responder is called without params for reading entries
* To add a new item the responder is called with param 'label'
*/
var dataStore = new Class({
    Implements: [Options, Events],
    debug: false,
    items: [],
    registeredElements: [],
    options: {
        async: false,
        items: [],
        // can be an array of objects or a JSON string
        readonly: false,
        url: undefined,
    },

    initialize: function(options) {
        this.setOptions(options);
        if (this.options.url) {
            this.url = this.options.url;
            this.refresh();
        } else {
            if (typeOf(this.options.items) == 'string')
                this.items = JSON.decode(this.options.items);
            else
                this.items = this.options.items;
        }
    },
    // Load from URL
    refresh: function() {
        new Request.JSON({
            url: this.url,
            async: this.options.async,
            onSuccess: function(json, text) {
                this.items = json;
            }.bind(this)
        }).get();
    },
    addItem: function(object) {
        /*
        * If it is possible (not readonly, not static)
        * try to add a new item.
        * - the added item, on success
        * - an error object, on failure (obj.error == true)
        */
        if (!this.url || this.options.readonly) {
            console.log('No url or readonly DS, cannot addItem');
            return null;
        }

        var req = new Request.JSON({
            url: this.url,
            data: {
                'item': JSON.encode(object)
            },
            async: this.options.async,
            onSuccess: function(json, text) {
                this.newItem = json;
            },
            onFailure: function(json, text) {
                this.newItem = {
                    error: true,
                    code: json.status,
                    text: json.statusText
                };
            }
        });
        req.send();
        if (req.status == 200) {
            this.items.include(req.newItem);
        }
        return req.newItem;
    },
    // search methods
    byField: function(field, value) {
        var selected;
        this.items.forEach(function(el) {
            if (Object.getFromPath(el, [field]) == value) {
                selected = el;
            }
        });
        return selected;
    },
    byId: function(id) {
        // Shortcut to get an item by id
        return this.byField('id', id);
    },
});

//
// Select with DS
// <select classs="selectDS" name="xxx" ds:id="id" ds:html="label">
//
var selectDS = new Class({
    Implements: [Options, Events],
    debug: false,
    options: {
        ds: undefined,
        id: 'id',
        html: 'label'
    },

    initialize: function(target, options) {
        this.setOptions(options);
        this.target = target;

        this.ds = this.options.ds
        this.id = this.target.hasAttribute('ds:id') ? this.target.get('ds:id') : this.options.id;
        this.html = this.target.hasAttribute('ds:html') ? this.target.get('ds:html') : this.options.html;
        this.value = this.target.hasAttribute('ds:value') ? this.target.get('ds:value') : undefined;
        this.fillOpt(this.value);
    },
    fillOpt: function(selectedVal) {
        // Fill options
        if (this.ds && this.ds.items.length) {
            Array.forEach(this.ds.items, function(el) {
                var option = new Element('option', {
                    'html': el[this.html],
                    'value': el[this.id]
                });
                if (el[this.id] == selectedVal) option.setAttribute('selected', 'selected');
                option.inject(this.target);
            }.bind(this));
        }
    },
    refresh: function() {
        this.target.getChildren('option').destroy();
        this.ds.refresh();
        this.fillOpt(this.value);
    }

});

function activeSelectDS(objectList, options) {
    if (!options) options = {};
    objectList.forEach(function(el) {
        new selectDS(el, options);
    });
}
/* ---------------------------------------------- */

//
// Numeric formatted input
// Formats a number with 'decimal' places in current locale
//
// Validator
//
Form.Validator.add('validate-formatted-number', {
    errorMsg: 'Please, enter a number',
    test: function(el, props) {
        var val = el.get('value');
        var gsep = Locale.get('Number').group.escapeRegExp();
        var returnValue = val.replace(new RegExp(gsep, 'g'), '').replace(Locale.get('Number').decimal, '.');
        return (!isNaN(Number(returnValue)));
    }
});

//
// Widgets
//
//
// Generic Numeric, decimals defaults to 0
//
var numericInput = new Class({
    Implements: [Options, Events],
    formattedElement: null,
    debug: true,
    options: {
        decimals: 0
    },

    initialize: function(target, options) {
        this.setOptions(options);
        this.target = target;

        var value = this.target.get('value');
        var formatted = parseFloat(value);

        this.formattedElement = this.target.clone();
        this.formattedElement.addClass('numeric');
        this.formattedElement.addClass('numericInput');
        this.formattedElement.addClass('validate-formatted-number');
        // this.formattedElement.set('style', 'width:120px;');

        this.target.hide();
        this.debug ? this.formattedElement.set('title', this.target.get('value')) : null;
        this.formattedElement.removeAttribute('name'); // Delete name, so it is not passed from form
        this.formattedElement.addEvent('change', function() {
            this.copyValues()
        }.bind(this));
        this.formattedElement.setAttribute('value', formatted.format({
            decimals: this.options.decimals
        }));
        this.formattedElement.inject(this.target, 'after');

    },
    cleanUp: function(num) {
        var gsep = Locale.get('Number').group.escapeRegExp();
        var returnValue = num.replace(new RegExp(gsep, 'g'), '').replace(Locale.get('Number').decimal, '.');
        return Number(returnValue);
    },
    copyValues: function() {
        var value = this.formattedElement.get('value');
        value = this.cleanUp(value);
        this.formattedElement.set('value', value.format({
            decimals: this.options.decimals
        }));
        this.target.set('value', value);
        this.debug ? this.formattedElement.set('title', this.target.get('value')) : null;
    },

});

// Shortcut for metric tons (3 decimal places)
var tonsInput = new Class({
    Extends: numericInput,
    options: {
        decimals: 3
    },
});

// Shortcut for decimal time (5 decimal places)
var timeInput = new Class({
    Extends: numericInput,
    options: {
        decimals: 5
    },
});

// Shortcut for money amount (2 decimal places)
var moneyInput = new Class({
    Extends: numericInput,
    options: {
        decimals: 2
    },
});

// Activators
function activeTonsInput(objectList, options) {
    objectList.forEach(function(el) {
        new tonsInput(el, options);
    });
}

function activeTimeInput(objectList, options) {
    objectList.forEach(function(el, options) {
        new timeInput(el, options);
    }.bind(this));
}

function activeMoneyInput(objectList, options) {
    objectList.forEach(function(el, options) {
        new moneyInput(el, options);
    }.bind(this));
}

/* ---------------------------------------- */

//
// MONEY WIDGET
// IN:  input id={ID} value=XXXX.XX,Y
// OUT: change target value
//
var widgetMoney = new Class({
    Implements: [Options, Events],
    amountElement: null,
    currencyElement: null,
    debug: true,
    options: {
        currencies: undefined,
        decimals: 2,
        currency: 'select' // plain - print symbol, select - create select, none - do not print
    },

    initialize: function(target, options) {
        this.setOptions(options);
        this.target = target;
        this.currencies = this.options.currencies;

        var value = this.target.get('value').split(',');
        var amount = parseFloat(value[0]);
        var currency_id = parseInt(value[1]);

        this.amountObj = new moneyInput(this.target);

        this.currencyObj = new selectDS(new Element('select', {
            style: 'width:70px; margin-left:5px;',
            'ds:value': currency_id
        }), {
            ds: this.currencies,
            html: 'html'
        });
        this.currencyObj.target.inject(this.amountObj.formattedElement, 'after');
        this.currencyObj.target.setProperty('disabled', this.target.getProperties('disabled', 'readonly'));

        // Events management
        var copyVals = function() {
            this.copyValues();
        }.bind(this);

        this.amountObj.formattedElement.removeEvents('change');
        this.amountObj.formattedElement.addEvent('change', copyVals);
        this.currencyObj.target.addEvent('change', copyVals);

    },
    copyValues: function() {
        var amount = this.amountObj.formattedElement.get('value');
        amount = this.amountObj.cleanUp(amount);

        var currency_id = this.currencyObj.target.get('value');
        var complexValue = amount + ',' + currency_id;

        this.target.set('value', complexValue);
        this.amountObj.formattedElement.set('title', complexValue);
        this.amountObj.formattedElement.set('value', amount.format({
            decimals: this.options.decimals
        }));

    }
});

function activeWidgetMoney(objectList, options) {
    currencies = [];
    if (!options) options = {};
    objectList.forEach(function(el) {
        new widgetMoney(el, options);
    });
}

